package myJs

import myJs.myPkg.jquery._
import org.scalajs.dom.ext.Ajax
import scalatags.Text.all._

import scala.collection.immutable.SeqMap
import scala.concurrent.ExecutionContext.Implicits.global
import scala.scalajs.js
import scala.scalajs.js.JSConverters._
import scala.scalajs.js.JSON
import scala.scalajs.js.annotation.{JSExport, JSExportTopLevel}
import myJs.Implicits._
import myJs.api.Api
import myJs.myPkg.{ColumnOptions, Select2Options, TableOptions}
import myJs.tool.Pojo.FilterContentData
import myJs.tool.Tool
import org.scalajs.dom.{Element, document}
import shared.VarTool

import scala.scalajs.js.Dynamic.{global => g}
import scala.scalajs.js.JSConverters._

/** Created by yz on 11/5/2020
  */
@JSExportTopLevel("Browse")
object Browse {

  val tableId = "table"

  @JSExport("init")
  def init = {
    initTable
    refreshSelect2("")
    refreshTable()
    registerEvent
  }

  def tableF = {
    val url = g.jsRoutes.controllers.BrowseController.getAllProkaryote().url.toString
    Ajax.get(url = s"${url.noCache}", headers = Map("Content-Type" -> "application/json")).map { xhr =>
      xhr.responseText.toJArJDJAn.toMyJDS
    }
  }

  def tbFmt(columnName: String): js.Function = (v: js.Any, row: js.Dictionary[js.Any]) =>
    columnName match {
      case "organismInfraspecificNamesStrain" =>
        val url = g.jsRoutes.controllers.BrowseController.detailInfoBefore().url.toString
        a(href := s"${url}?id=${row("bioSample")}", cursor.pointer, target := "_blank", v.toString)
      case "bioSample" =>
        a(href := s"https://www.ncbi.nlm.nih.gov/biosample/${v}", cursor.pointer, target := "_blank", v.toString)
      case "assembly" =>
        a(href := s"https://www.ncbi.nlm.nih.gov/assembly/${v}", cursor.pointer, target := "_blank", v.toString)
      case "assemblyLevel" =>
        val imageFileName = v.toString match {
          case "Chromosome" => "threequarters.gif"
          case "Complete Genome" => "complete.gif"
          case "Contig" => "quarter.gif"
          case "Scaffold" => "half.gif"
        }
        img(src := s"/mtd/assets/images/${imageFileName}", title := s"${v}")
      case "assemblyStatsTotalSequenceLength" =>
        (v.toString.toDouble / (1000.0 * 1000)).toFixed(2)
      case _ => v
    }

  def expStyle(columnName: String): js.Function = (v: js.Any, row: js.Dictionary[Any]) =>
    columnName match {
      case _ => v
    }

  def sortExec(data: JArJDS, queryMap: Map[String, js.Array[String]]) = {
    val sortOp = queryMap.get("sort").map(_.head)
    val sortData = sortOp
      .map { sort =>
        val isRange = $(s"#${sort}Content").find(".rangeInput").length > 0
        val ascSortData = if (isRange) {
          data.sortBy(_(sort).toDouble)
        } else {
          data.sortBy(_(sort))
        }
        queryMap("order").head match {
          case "desc" => ascSortData.reverse
          case "asc" => ascSortData
        }
      }
      .getOrElse(data)
    sortData
  }

  @JSExport("filterContentShow")
  def filterContentShow(y: Element) = {
    $(".filterContent").hide()
    val fieldName = Tool.getFilterDataFieldName(y)
    val contentId = s"#${fieldName}Content"
    val yTop = $(y).offset().top + $(y).height() + 2
    val pageWidth = document.body.clientWidth
    val yTotalLeft = $(y).offset().left
    val leftWidth = $("#myLeft").width()
    val yLeft = yTotalLeft - leftWidth
    val width = 210
    val trueYLeft = if (yTotalLeft + width > pageWidth) pageWidth - leftWidth - 220 - 6 else yLeft - 3
    $(s"${contentId}").css("top", yTop.toInt).css("left", trueYLeft.toInt).width(width)
    $(s"${contentId}").show()
    Tool.filterContentFillBeforeValue($(s"${contentId}"))
  }

  def registerEvent = {
    tableFilterEvent
  }

  def tableFilterEvent = {
    Tool.clickHide

    $(document.body).on(
      "click",
      ".myOperate",
      "",
      (y: Element) => {
        filterContentShow(y)
      }
    )
    $(document.body).on(
      "click",
      ".mySortLi",
      "",
      (y: Element) => {
        Tool.execSort(
          y,
          "",
          () => {
            refreshTable()
          }
        )
      }
    )
    $(document.body).on(
      "click",
      ".myConfirm",
      "",
      (y: Element) => {
        Tool.confirmFilter(
          y,
          "",
          () => {
            refreshTable()
          }
        )
      }
    )
    $(document.body).on(
      "click",
      ".myHide",
      "",
      (y: Element) => {
        Tool.hideFilterContent(y)
      }
    )
    $(document.body).on(
      "click",
      s".myRemove",
      "",
      (y: Element) => {
        Tool.removeCondition(
          y,
          "",
          () => {
            refreshTable()
          }
        )
      }
    )
    $(document.body).on(
      "click",
      s".myRemoveSort",
      "",
      (y: Element) => {
        Tool.removeSort(
          y,
          "",
          () => {
            refreshTable()
          }
        )
      }
    )
  }

  def initFilterContent(tabId: String = "", map: SeqMap[String, String]) = {
    val textSortDatas =
      List(
        "organismInfraspecificNamesStrain",
        "bioSample",
        "assembly",
        "assemblyName",
        "organismName",
        "organismInfraspecificNamesIsolate",
        "annotationName"
      ).map { fieldName =>
        FilterContentData(fieldName, map(fieldName))
      }
    val select2SortDatas = List(
      FilterContentData("assemblyLevel", "Assembly Level", List.empty)
    )
    val rangeSortDatas = List("assemblyStatsTotalSequenceLength").map { fieldName =>
      FilterContentData(fieldName, map(fieldName))
    }
    val timeSortDatas = List("assemblyReleaseDate").map { fieldName =>
      FilterContentData(fieldName, map(fieldName))
    }

    Tool.initFilterContent(
      textSortDatas = textSortDatas,
      select2SortDatas = select2SortDatas,
      rangeSortDatas = rangeSortDatas,
      timeSortDatas = timeSortDatas,
      parentId = s"${tabId}"
    )
    textSortDatas ::: select2SortDatas ::: rangeSortDatas ::: timeSortDatas
  }

  def refreshSelect2(parentId: String) = {
    refreshLevel(parentId)
  }

  def refreshLevel(parentId: String) = {
    val inputName = "assemblyLevel"
    val data = List("Chromosome", "Complete", "Contig", "Scaffold")
    val array = (data).map { v =>
      js.Dictionary("text" -> v, "id" -> v)
    }
    val parentJq = Tool.getParentJq(parentId)
    val options =
      Select2Options(data=array.toJSArray,multiple=true,placeholder="click to choose",dropdownParent=parentJq)
    parentJq.findInputByName(inputName).select2(options)
  }

  def initTable = {
    val map = VarTool.browseMap
    val allDatas = initFilterContent("", map)
    val columnNames = map.keyList
    val columns = columnNames.map { columnName =>
      val title = map.getOrElse(columnName, columnName)
      val fmt = tbFmt(columnName)
      val style = expStyle(columnName)
      val basicOptions = ColumnOptions.field(columnName).title(title).sortable(true).formatter(fmt).cellStyle(style)
      columnName match {
        case x if allDatas.map(_.fieldName).contains(x) => basicOptions.sortable(false).operateable(true)
        case "level" => basicOptions.`class`("myImgTd")
        case _ => basicOptions
      }
    }
    val options = TableOptions
      .columns(columns.toJSArray)
      .searchOnButton(false)
      .filterControl(false)
      .idField("id")
      .parentIdField("pId")
      .treeShowField("fileName")
      .treeEnable(true)
      .rootParentId("0")
    $(s"#${tableId}").bootstrapTable(options)
    Tool.dateInit
    Tool.refreshCheckboxView(map.tail)

    map.keyList.drop(8).foreach { x =>
      $("#table").bootstrapTable("hideColumn", x)
      $(s"input:checkbox[value='${x}']").attr("checked", false)
    }

  }

  def refreshTable(f: () => js.Any = () => ()) = {
    val queryMap = Tool.getFrontQueryMap("")
    println(queryMap)
    tableF.map { data =>
      val sortData = sortExec(data, queryMap)

      def loopFilter(sortData: JArJDS) = {

        val filterColumns = queryMap.removedAll(List("sort", "order")).filter(_._2.map(_.trim).nonEmpty).keyList

        def loop(acc: JArJDS, elems: List[String]): JArJDS = {
          elems match {
            case Nil => acc
            case y :: ys =>
              val searchV = queryMap(y)
              val vs = searchV
              val trueSearchV = searchV.head
              val fieldName = y.split("\\.")(0)
              val name = y.split("\\.")(1)
              val jq = $(s"#${fieldName}Content").findInputByName(name)
              val curFilterData = if (jq.hasClass("myDatepicker")) {
                acc.filter { row =>
                  val dbDate = row(fieldName)
                  if (name == "startTime") {
                    Tool.timeBefore(vs.head, dbDate)
                  } else {
                    Tool.timeAfter(vs.head, dbDate)
                  }
                }
              } else if (jq.hasClass("select2MultiInput")) {
                acc.filter { row =>
                  vs.exists(row(fieldName) == _)
                }
              } else if (jq.hasClass("rangeInput")) {
                acc.filter { row =>
                  val dbDouble = row(fieldName).toDouble
                  val v = vs.head
                  if (v.isDouble) {
                    if (name == "min") {
                      dbDouble >= vs.head.toDouble
                    } else {
                      dbDouble <= vs.head.toDouble
                    }
                  } else {
                    false
                  }
                }
              } else {
                acc.filter { row =>
                  row(fieldName).contains(vs.head)
                }
              }
              loop(curFilterData, ys)
          }
        }

        loop(sortData, filterColumns)
      }

      val filterData = loopFilter(sortData)
      $(s"#${tableId}").bootstrapTable("load", filterData)
      f()
    }
  }

}
